/*
 * ActionTest.java
 *
 *  
 */
package org.msb.finance.app;

import static javax.swing.Action.ACCELERATOR_KEY;
import static javax.swing.Action.DISPLAYED_MNEMONIC_INDEX_KEY;
import static javax.swing.Action.MNEMONIC_KEY;
import static javax.swing.Action.NAME;
import static org.junit.Assert.assertEquals;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

import javax.swing.Icon;
import javax.swing.KeyStroke;

import org.junit.Test;

/**
 * 
 * 
 * @author boudream
 * 
 */
public class ActionTest {

	/**
	 * Test method for {@link org.msb.finance.app.Action#parseActionDefinition(java.lang.String)}.
	 */
	@SuppressWarnings("nls")
	@Test
	public void testParseActionDefinition() {
		assertActionState("", "", '\0', -1, null);
		assertActionState("@", "@", '\0', -1, null);
		assertActionState("&", "&", '\0', -1, null);
		assertActionState("&@", "@", '@', 0, null);

		/*
		 * @& is invalid because there is no VK_& constant. The correct syntax would be shift 7.
		 */
		assertActionState("@&", "", '\0', -1, null);

		assertActionState("&New@ctrl N", "New", 'N', 0, KeyStroke
				.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK));
		assertActionState("&Save && Close@F12", "Save & Close", 'S', 0, KeyStroke.getKeyStroke(KeyEvent.VK_F12, 0));
		assertActionState("Save && &Close@ctrl alt F12", "Save & Close", 'C', 7, KeyStroke.getKeyStroke(
				KeyEvent.VK_F12, InputEvent.ALT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK));

		assertActionState("Look @@ you@F2", "Look @ you", '\0', -1, KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0));
	}

	/*
	 * Creates an Action object, parses the provided input String and asserts that the name, mnemonic, mnemonic index,
	 * and accelerator properties have been set to the specified expected values.
	 */
	private void assertActionState(String input, String expectedName, char expectedMnemonic, int expectedMnemonicIndex,
			KeyStroke expectedKeyStroke) {
		Action action = new Action();
		action.parseActionDefinition(input);

		assertEquals("Unexpected Name value set in Action.", expectedName, action.getValue(NAME)); //$NON-NLS-1$
		assertEquals(
				"Unexpected Mnemonic value set in Action.", new Integer(expectedMnemonic), action.getValue(MNEMONIC_KEY)); //$NON-NLS-1$
		assertEquals(
				"Unexpected Mnemonic Index value set in Action.", expectedMnemonicIndex, action.getValue(DISPLAYED_MNEMONIC_INDEX_KEY)); //$NON-NLS-1$
		assertEquals("Unexpected Accelerator value set in Action.", expectedKeyStroke, action.getValue(ACCELERATOR_KEY)); //$NON-NLS-1$
	}

	/**
	 * 
	 */
	@Test
	public void testActionConstructors() {
		assertActionCompleteState(new Action(), null, null, null, null, null, null, null, true, null, null);

		FakeActionListener fal = new FakeActionListener();
		assertActionCompleteState(new Action(fal), fal, null, null, null, null, null, null, true, null, null);

		FakeResources fr = new FakeResources("testkey"); //$NON-NLS-1$
		FakeActionEnabledCallback faecb = new FakeActionEnabledCallback(false);
		assertActionCompleteState(
				new Action(fal, fr, "testkey", "theCommand", false, true, faecb), //$NON-NLS-1$ //$NON-NLS-2$
				fal, "theName", null, "theCommand", new Integer('m'), new Integer(5), KeyStroke.getKeyStroke("ctrl M"),
				false, true, faecb);

		assertActionCompleteState(new Action(fal, "theName", null, "theCommand", 'M', 2, "theTooltip", KeyStroke //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
				.getKeyStroke('F'), false, true, null), fal, "theName", null, "theCommand", new Integer('M'), //$NON-NLS-1$//$NON-NLS-2$
				new Integer(2), KeyStroke.getKeyStroke('F'), false, Boolean.TRUE, null);
	}

	private void assertActionCompleteState(Action action, ActionListener expectedDelegate, String expectedName,
			Icon expectedIcon, String expectedCommand, Integer expectedMnemonic, Integer expectedMnemonicIndex,
			KeyStroke expectedAccelerator, boolean expectedEnabled, Boolean expectedSelected,
			ActionEnabledCallback expectedCallback) {
		//
	}

	/**
	 * 
	 */
	@Test
	public void testActionPerformed() {
		FakeActionListener fal = new FakeActionListener();
		Action action = new Action(fal);

		action.actionPerformed(null);
		assertEquals(1, fal.count);

		action.actionPerformed(null);
		action.actionPerformed(null);
		assertEquals(3, fal.count);
	}

	/**
	 * 
	 */
	@Test
	public void testStateChanged() {
		FakeActionEnabledCallback faecb = new FakeActionEnabledCallback(true);
		Action action = new Action(null, null, null, null, '\0', -1, null, null, true, false, faecb);
		assertEquals(true, action.isEnabled());

		action.stateChanged(null);
		assertEquals(false, action.isEnabled());

		action.stateChanged(null);
		assertEquals(true, action.isEnabled());
	}

	private class FakeActionListener implements ActionListener {

		private int count;

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e) {
			++this.count;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		@Override
		public boolean equals(Object obj) {
			return (null != obj && obj.getClass() == FakeActionListener.class);
		}
	}

	private class FakeResources extends Resources {

		/*
		 * 
		 */
		private Map<String, Object> resources = new HashMap<String, Object>();

		/**
		 * @param prefix
		 */
		public FakeResources(String prefix) {
			super((ResourceBundle) null);

			this.resources.put(prefix, "theNa&me@ctrl N"); //$NON-NLS-1$
			this.resources.put(prefix + ".icon", null); //$NON-NLS-1$
			this.resources.put(prefix + ".tooltip", "theTooltip"); //$NON-NLS-1$ //$NON-NLS-2$
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.msb.finance.app.Resources#getIcon(java.lang.String)
		 */
		@Override
		public Icon getIcon(String key) {
			return (Icon) this.resources.get(key);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.msb.finance.app.Resources#getString(java.lang.String)
		 */
		@Override
		public String getString(String key) {
			return (String) this.resources.get(key);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		@Override
		public boolean equals(Object obj) {
			return (null != obj && obj.getClass() == FakeResources.class);
		}
	}

	/*
	 * 
	 */
	private class FakeActionEnabledCallback implements ActionEnabledCallback {

		/*
		 * 
		 */
		private boolean lastValue;

		/**
		 * 
		 * @param state
		 */
		public FakeActionEnabledCallback(boolean state) {
			this.lastValue = state;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.msb.finance.app.ActionEnabledCallback#isEnabled()
		 */
		public boolean isEnabled() {
			this.lastValue = !this.lastValue;
			return this.lastValue;
		}

	}
}
